#ifndef CUSTOM_RC_COMBINE_INCLUDED
#define CUSTOM_RC_COMBINE_INCLUDED

#include "RCCommon.hlsl"

// Uniform Parameter
uniform int Cascade_Level;                          // Current Cascade Level n
uniform float Cascade_Marching_Begin;               // Sample From [Cascade_MarchingLength_Base * pow(2, n)] To [Cascade_MarchingLength_Base * pow(2, n + 1)]
uniform float Cascade_Marching_End;                 // Sample From [Cascade_MarchingLength_Base * pow(2, n)] To [Cascade_MarchingLength_Base * pow(2, n + 1)]

uniform Texture2D _BlueNoiseTex;
Texture2D _BlitTexture;                             // Pre-calced RayMaching Result
SamplerState sampler_BlueNoiseTex;

float4 MergePass(in ProbeInfo Probe) {
    int AngleLocalIndex     = Probe.AngleLocalPix.x + Probe.AngleLocalPix.y * Probe.AngleSize.x;
    float2 AngleSize_Np1    = Cascade_ProbeSize_AngleSize[Cascade_Level + 1].zw;
    // Merge
    float4 LDResult = SampleCascade(_BlitTexture, (Probe.Probe - 1) / 2 + int2(0, 0), AngleSize_Np1, AngleLocalIndex * 4, 4);
    float4 RDResult = SampleCascade(_BlitTexture, (Probe.Probe - 1) / 2 + int2(1, 0), AngleSize_Np1, AngleLocalIndex * 4, 4);
    float4 LUResult = SampleCascade(_BlitTexture, (Probe.Probe - 1) / 2 + int2(0, 1), AngleSize_Np1, AngleLocalIndex * 4, 4);
    float4 RUResult = SampleCascade(_BlitTexture, (Probe.Probe - 1) / 2 + int2(1, 1), AngleSize_Np1, AngleLocalIndex * 4, 4);
    
    float BilinearU = 0.25 + 0.5 * ((Probe.Probe.x - 1) & 1);
    float BilinearV = 0.25 + 0.5 * ((Probe.Probe.y - 1) & 1);

    return BilinearLerp(LDResult, RDResult, LUResult, RUResult, float2(BilinearU, BilinearV));
}

#define RayMarchingCount 1

float4 RayMarchingPass(in ProbeInfo Probe) {
    // Position
    float2 ProbePixPos = Probe.Probe * Probe.ProbeLength + Probe.ProbeLength / 2;

    // Angle
    float AngleLocalIndex   = Probe.AngleLocalPix.x + Probe.AngleLocalPix.y * Probe.AngleSize.x;
    // Noise
    const float NoiseFluence = 1.0f / RayMarchingCount;
    float2 NoiseUV = Probe.TexUV;
    float Noise         = _BlueNoiseTex.Sample(sampler_BlueNoiseTex, NoiseUV).x;
    float NoiseAngle    = Noise * NoiseFluence * 2.0 - NoiseFluence;
    
    // Deal With Marching Result
    float4 Result = float4(0.0, 0.0, 0.0, 0.0);
    [unroll] 
    for (int RayMarchingIndex = 1; RayMarchingIndex <= RayMarchingCount; RayMarchingIndex++) {
        float   MarchingAngle   = ((AngleLocalIndex + RayMarchingIndex * 1.0 / (RayMarchingCount + 1) + NoiseAngle) / Probe.AngleSize.x / Probe.AngleSize.y) * 2 * PI;
        float2  MarchingDir     = float2(cos(MarchingAngle), sin(MarchingAngle));
        Result += RayMarching((ProbePixPos / _ScreenParams.y) + Cascade_Marching_Begin * MarchingDir, MarchingDir, Cascade_Marching_End - Cascade_Marching_Begin);
    }
    Result /= RayMarchingCount;
    
    return Result;
}

float4 RCCombineFragment(Vert2Frag Input) : SV_TARGET {
    ProbeInfo Probe = GetProbeInfo(Cascade_Level, Input.ScreenUV);

    float4 MergeResult = MergePass(Probe);
    float4 RayMarchingResult = RayMarchingPass(Probe);
    
    float4 Result;
    Result.rgb  = MergeResult.rgb * RayMarchingResult.a + RayMarchingResult.rgb;
    Result.a    = RayMarchingResult.a * MergeResult.a;

    return Result;
}
#endif